//
// Copyright 2022 DMetaSoul
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#include <algorithm>
#include <common/hashmap/hashtable_helpers.h>
#include <iostream>
#include <stack>

namespace metaspore {

uint64_t HashtableHelpers::get_prime_bucket_count(uint64_t min_size) {
    static const unsigned long primes[] = {
        0x0000000000000002UL, 0x0000000000000003UL, 0x0000000000000005UL, 0x0000000000000007UL,
        0x000000000000000BUL, 0x000000000000000DUL, 0x0000000000000011UL, 0x0000000000000013UL,
        0x0000000000000017UL, 0x000000000000001DUL, 0x000000000000001FUL, 0x0000000000000025UL,
        0x0000000000000029UL, 0x000000000000002BUL, 0x000000000000002FUL, 0x0000000000000035UL,
        0x000000000000003BUL, 0x000000000000003DUL, 0x0000000000000043UL, 0x0000000000000047UL,
        0x0000000000000049UL, 0x000000000000004FUL, 0x0000000000000053UL, 0x0000000000000059UL,
        0x0000000000000061UL, 0x0000000000000067UL, 0x000000000000006DUL, 0x0000000000000071UL,
        0x000000000000007FUL, 0x0000000000000089UL, 0x000000000000008BUL, 0x0000000000000095UL,
        0x000000000000009DUL, 0x00000000000000A7UL, 0x00000000000000B3UL, 0x00000000000000C1UL,
        0x00000000000000C7UL, 0x00000000000000D3UL, 0x00000000000000E3UL, 0x00000000000000F1UL,
        0x0000000000000101UL, 0x0000000000000115UL, 0x0000000000000125UL, 0x0000000000000139UL,
        0x0000000000000151UL, 0x0000000000000167UL, 0x000000000000017FUL, 0x0000000000000199UL,
        0x00000000000001B7UL, 0x00000000000001D3UL, 0x00000000000001F7UL, 0x000000000000021DUL,
        0x0000000000000241UL, 0x000000000000026BUL, 0x0000000000000295UL, 0x00000000000002C5UL,
        0x00000000000002F9UL, 0x0000000000000337UL, 0x0000000000000377UL, 0x00000000000003B9UL,
        0x0000000000000407UL, 0x0000000000000455UL, 0x00000000000004A9UL, 0x0000000000000509UL,
        0x0000000000000565UL, 0x00000000000005D5UL, 0x000000000000064DUL, 0x00000000000006CDUL,
        0x0000000000000757UL, 0x00000000000007EDUL, 0x0000000000000883UL, 0x0000000000000935UL,
        0x00000000000009F5UL, 0x0000000000000AC1UL, 0x0000000000000B9BUL, 0x0000000000000C89UL,
        0x0000000000000D8DUL, 0x0000000000000E9BUL, 0x0000000000000FBBUL, 0x00000000000010FDUL,
        0x000000000000125FUL, 0x00000000000013DFUL, 0x000000000000157FUL, 0x0000000000001741UL,
        0x000000000000191BUL, 0x0000000000001B25UL, 0x0000000000001D5DUL, 0x0000000000001FBBUL,
        0x000000000000224FUL, 0x0000000000002519UL, 0x0000000000002821UL, 0x0000000000002B69UL,
        0x0000000000002EEBUL, 0x00000000000032B7UL, 0x00000000000036D1UL, 0x0000000000003B45UL,
        0x000000000000401BUL, 0x0000000000004555UL, 0x0000000000004AEFUL, 0x0000000000005111UL,
        0x00000000000057AFUL, 0x0000000000005ED9UL, 0x000000000000669BUL, 0x0000000000006EFBUL,
        0x0000000000007807UL, 0x00000000000081C7UL, 0x0000000000008C5DUL, 0x00000000000097D9UL,
        0x000000000000A43BUL, 0x000000000000B1A9UL, 0x000000000000C031UL, 0x000000000000CFD1UL,
        0x000000000000E0D5UL, 0x000000000000F319UL, 0x00000000000106EBUL, 0x0000000000011C71UL,
        0x00000000000133BBUL, 0x0000000000014CEDUL, 0x000000000001682BUL, 0x0000000000018595UL,
        0x000000000001A579UL, 0x000000000001C7FBUL, 0x000000000001ED3FUL, 0x000000000002159FUL,
        0x0000000000024151UL, 0x000000000002707FUL, 0x000000000002A385UL, 0x000000000002DAD3UL,
        0x00000000000316A9UL, 0x000000000003575BUL, 0x0000000000039D61UL, 0x000000000003E917UL,
        0x0000000000043B0DUL, 0x00000000000493AFUL, 0x000000000004F397UL, 0x0000000000055B55UL,
        0x000000000005CB8BUL, 0x00000000000644E9UL, 0x000000000006C847UL, 0x0000000000075671UL,
        0x000000000007F031UL, 0x0000000000089699UL, 0x0000000000094A87UL, 0x00000000000A0D41UL,
        0x00000000000ADFF9UL, 0x00000000000BC3E9UL, 0x00000000000CBA85UL, 0x00000000000DC553UL,
        0x00000000000EE5F1UL, 0x0000000000101E43UL, 0x0000000000117025UL, 0x000000000012DDADUL,
        0x000000000014691DUL, 0x00000000001614F1UL, 0x000000000017E3DBUL, 0x000000000019D8A3UL,
        0x00000000001BF671UL, 0x00000000001E40A3UL, 0x000000000020BAD1UL, 0x00000000002368F3UL,
        0x0000000000264F3DUL, 0x0000000000297259UL, 0x00000000002CD737UL, 0x0000000000308327UL,
        0x0000000000347C23UL, 0x000000000038C857UL, 0x00000000003D6EAFUL, 0x000000000042767BUL,
        0x000000000047E7BDUL, 0x00000000004DCB13UL, 0x00000000005429D1UL, 0x00000000005B0DF3UL,
        0x00000000006282C7UL, 0x00000000006A93B5UL, 0x0000000000734DE3UL, 0x00000000007CBF17UL,
        0x000000000086F63BUL, 0x0000000000920377UL, 0x00000000009DF84DUL, 0x0000000000AAE7E9UL,
        0x0000000000B8E6B9UL, 0x0000000000C80ADFUL, 0x0000000000D86C73UL, 0x0000000000EA256FUL,
        0x0000000000FD51F9UL, 0x0000000001121077UL, 0x00000000012881DBUL, 0x000000000140C9B9UL,
        0x00000000015B0E8DUL, 0x0000000001777A0BUL, 0x000000000196396DUL, 0x0000000001B77D61UL,
        0x0000000001DB7A95UL, 0x0000000002026A59UL, 0x00000000022C8A63UL, 0x00000000025A1D87UL,
        0x00000000028B6C13UL, 0x0000000002C0C435UL, 0x0000000002FA7AB7UL, 0x000000000338EB19UL,
        0x00000000037C786FUL, 0x0000000003C58DE1UL, 0x0000000004149F67UL, 0x00000000046A2A75UL,
        0x0000000004C6B6EBUL, 0x00000000052AD787UL, 0x0000000005972B2DUL, 0x00000000060C5DB5UL,
        0x00000000068B2929UL, 0x0000000007145695UL, 0x0000000007A8BFDDUL, 0x0000000008495051UL,
        0x0000000008F706BBUL, 0x0000000009B2F6F9UL, 0x000000000A7E4B0DUL, 0x000000000B5A4593UL,
        0x000000000C4843C3UL, 0x000000000D49BF31UL, 0x000000000E60505DUL, 0x000000000F8DB15BUL,
        0x0000000010D3C05FUL, 0x00000000123482BDUL, 0x0000000013B2284DUL, 0x00000000154F0E89UL,
        0x00000000170DC4A5UL, 0x0000000018F10F85UL, 0x000000001AFBEE09UL, 0x000000001D319DC9UL,
        0x000000001F95A075UL, 0x00000000222BC111UL, 0x0000000024F81A5DUL, 0x0000000027FF1CF1UL,
        0x000000002B4596A5UL, 0x000000002ED0B9B7UL, 0x0000000032A625E7UL, 0x0000000036CBF04BUL,
        0x000000003B48ADD5UL, 0x0000000040237D21UL, 0x0000000045641269UL, 0x000000004B12C31FUL,
        0x0000000051389375UL, 0x0000000057DF44D7UL, 0x000000005F1164D1UL, 0x0000000066DA5EADUL,
        0x000000006F468CAFUL, 0x0000000078634C43UL, 0x00000000823F12D9UL, 0x000000008CE98529UL,
        0x0000000098738FBDUL, 0x00000000A4EF81F7UL, 0x00000000B2712B0FUL, 0x00000000C10DF951UL,
        0x00000000D0DD1CAFUL, 0x00000000E1F7AB4BUL, 0x00000000F478C8AFUL, 0x00000000FFFFFFFBUL,
        0x000000017FFFFFF5UL, 0x00000001FFFFFFF7UL, 0x00000002FFFFFFE1UL, 0x00000003FFFFFFD7UL,
        0x00000005FFFFFFADUL, 0x00000007FFFFFFE1UL, 0x0000000BFFFFFF47UL, 0x0000000FFFFFFFFBUL,
        0x00000017FFFFFFEFUL, 0x0000001FFFFFFFE7UL, 0x0000002FFFFFFFABUL, 0x0000003FFFFFFFD3UL,
        0x0000005FFFFFFFE3UL, 0x0000007FFFFFFFF9UL, 0x000000BFFFFFFF9BUL, 0x000000FFFFFFFFA9UL,
        0x0000017FFFFFFFABUL, 0x000001FFFFFFFFEBUL, 0x000002FFFFFFFFEDUL, 0x000003FFFFFFFFF5UL,
        0x000005FFFFFFFFCFUL, 0x000007FFFFFFFFC7UL, 0x00000BFFFFFFFFB9UL, 0x00000FFFFFFFFFEFUL,
        0x000017FFFFFFFFD5UL, 0x00001FFFFFFFFFC9UL, 0x00002FFFFFFFFFB9UL, 0x00003FFFFFFFFFEBUL,
        0x00005FFFFFFFFF9FUL, 0x00007FFFFFFFFF8DUL, 0x0000BFFFFFFFFF7DUL, 0x0000FFFFFFFFFFC5UL,
        0x0001FFFFFFFFFFAFUL, 0x0003FFFFFFFFFFE5UL, 0x0007FFFFFFFFFF7FUL, 0x000FFFFFFFFFFFD1UL,
        0x001FFFFFFFFFFF91UL, 0x003FFFFFFFFFFFDFUL, 0x007FFFFFFFFFFFC9UL, 0x00FFFFFFFFFFFFFBUL,
        0x01FFFFFFFFFFFFF3UL, 0x03FFFFFFFFFFFFE5UL, 0x07FFFFFFFFFFFFC9UL, 0x0FFFFFFFFFFFFFA3UL,
        0x1FFFFFFFFFFFFFFFUL, 0x3FFFFFFFFFFFFFC7UL, 0x7FFFFFFFFFFFFFE7UL, 0xFFFFFFFFFFFFFFC5UL,
        0xFFFFFFFFFFFFFFC5UL};
    const uint64_t num_primes = sizeof primes / sizeof primes[0] - 1;
    const unsigned long *const last = primes + num_primes;
    const unsigned long *const p = std::lower_bound(primes, last, min_size);
    return static_cast<uint64_t>(*p);
}

extern "C" size_t GetPeakRSS(void);
extern "C" size_t GetCurrentRSS(void);

size_t HashtableHelpers::get_peak_rss() { return GetPeakRSS(); }

size_t HashtableHelpers::get_current_rss() { return GetCurrentRSS(); }

void HashtableHelpers::show_memory_usage() {
    const size_t peak_rss = GetPeakRSS();
    const size_t cur_rss = GetCurrentRSS();
    std::cout << "   Peak RSS: " << peak_rss << " bytes = ";
    std::cout << (double(peak_rss) / 1024 / 1024 / 1024) << " GB" << std::endl;
    std::cout << "Current RSS: " << cur_rss << " bytes = ";
    std::cout << (double(cur_rss) / 1024 / 1024 / 1024) << " GB" << std::endl;
}

std::ostream &operator<<(std::ostream &sout, __uint128_t value) {
    std::stack<uint64_t> parts;
    while (value) {
        const __uint128_t base = UINT64_C(10000000000000000000);
        const __uint128_t quot = value / base;
        const __uint128_t rem = value % base;
        parts.push(rem);
        value = quot;
    }
    while (!parts.empty()) {
        sout << parts.top();
        parts.pop();
    }
    return sout;
}

} // namespace metaspore